import type { BodyOptions, QueryOptions } from '../global.d';

/**
 * 该文件可自行根据业务逻辑进行调整
 */
import { preferences } from '@vben/preferences';
import { useAccessStore } from '@vben/stores';

import { createAlova } from 'alova';
import { createServerTokenAuthentication } from 'alova/client';
import fetchAdapter from 'alova/fetch';
import vueHook from 'alova/vue';
import { message } from 'ant-design-vue';
import { merge } from 'lodash-es';

import { useAuthStore } from '#/store';

import { ACCESS_TOKEN_FIELD, getBaseURL } from './config';
import { getAccessToken } from './getToken';
import { transferResponse } from './transferResponse';

/** 储存过期的token */
let expireTokenCache: string[] = [];

/** 服务端 Token 校验 */
const { onAuthRequired, onResponseRefreshToken } =
  createServerTokenAuthentication({
    refreshTokenOnSuccess: {
      /**
       * 判断 Token 是否过期
       * 响应时触发，可获取到response和method，并返回boolean表示token是否过期
       */
      isExpired: async (response, method) => {
        // 文件下载操作
        if (method.meta?.responseType === 'blob') {
          return false;
        }

        const responseClone = response.clone();
        const data = await responseClone.json();

        // 当服务端返回401时，表示token过期
        const isExpired = ['A0013'].includes(data.code);
        if (isExpired) {
          console.log('AccessToken已过期', data.code);
          expireTokenCache.push(method.config.headers[ACCESS_TOKEN_FIELD]);
        }

        return isExpired;
      },
      /** 当token过期时触发，在此函数中触发刷新token */
      handler: async (_response, _method) => {
        console.warn('Access token or refresh token is invalid or expired. ');
        const accessStore = useAccessStore();
        const authStore = useAuthStore();
        // accessStore.setAccessToken(null);
        // if (
        //   preferences.app.loginExpiredMode === 'modal' &&
        //   accessStore.isAccessChecked
        // ) {
        //   accessStore.setLoginExpired(true);
        // } else {
        //   await authStore.logout(false);
        // }
        // throw new Error('登录已过期，请重新登录');

        // const userStore = useUserStore();
        try {
          const rToken = accessStore.refreshToken;
          // 如果没有refreshToken，则跳转登录页
          if (!rToken) {
            throw new Error('登录已过期，请重新登录');
          }
          await getAccessToken(rToken);
          expireTokenCache = [];
        } catch (error: any) {
          accessStore.setLoginExpired(true);
          message.error(error.message);
          await authStore.logout(false);
          // throw new Error('登录已过期，请重新登录');
          // userStore.resetStore();
          throw error;
        }
      },
    },
  });

export const alovaInstance = createAlova({
  /** 动态代理配置 */
  baseURL: getBaseURL(),
  /** 框架请求适配器 */
  statesHook: vueHook,
  requestAdapter: fetchAdapter(),
  /** 设置缓存状态：不开启 */
  cacheFor: null,
  // cacheFor: {
  //   // 统一设置POST的缓存模式
  //   GET: {
  //     mode: 'restore',
  //     expire: 60 * 10 * 1000,
  //   },
  //   // POST: {
  //   //   mode: 'restore',
  //   //   expire: 60 * 10 * 1000
  //   // },
  //   // // 统一设置HEAD请求的缓存模式
  //   // HEAD: 60 * 10 * 1000
  // },
  /** 请求拦截器 */
  beforeRequest: onAuthRequired((method) => {
    const accessStore = useAccessStore();

    if (accessStore.accessToken) {
      // method.config.headers.Token = accessStore.accessToken;
      // 统一授权的这个接口需要以Authorization传参，无语 /sys/user/functiontree/XTBGXT
      method.config.headers.Authorization = `Bearer ${accessStore.accessToken}`;
    }
    method.config.headers['Accept-Language'] = preferences.app.locale;

    // const userStore = useUserStore()
    // // 添加token到请求头
    // if (userStore.accessToken) {
    //   method.config.headers[ACCESS_TOKEN_FIELD] = `Bearer ${userStore.accessToken}`

    //   method.config.headers["Authorization"] = `Bearer ${userStore.accessToken}`
    // }

    // method.config.cacheFor = {
    //   // 设置缓存模式为内存模式
    //   mode: 'restore',
    //   // 单位为毫秒
    //   // 当设置为`Infinity`，表示数据永不过期，设置为0或负数时表示不缓存
    //   expire: 60 * 10 * 1000
    // }
    // method.config.transform = (rawData, headers) => {
    //   console.log('接口响应', rawData)
    //   return transferResponse(rawData)
    // }
  }),
  /** 响应拦截器 */
  responded: onResponseRefreshToken(async (response, method) => {
    if (response.status === 200 && method.meta?.responseType === 'blob') {
      const blob = await response.blob();
      const url = window.URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      const contentDisposition = response.headers.get('content-disposition');
      let fileName = 'downloaded-file';
      if (contentDisposition) {
        const matches = /filename="?([^"]+)"?/.exec(contentDisposition);
        if (matches != null && matches[1]) {
          fileName = decodeURIComponent(matches[1]);
        }
      }
      a.download = fileName;
      if (method.meta?.autoDownload !== false) {
        // 触发下载
        document.body.append(a);
        a.click();
        // 移除链接
        a.remove();
        window.URL.revokeObjectURL(url);
      }

      return {
        blob,
        url,
        filename: fileName,
      };
    }

    // if (response.status >= 400) {
    //   throw new Error(response.statusText);
    // }

    let json = await response.json();
    console.log('【接口】', method.url);
    console.log('原始响应', JSON.parse(JSON.stringify(json)));

    json = transferResponse(json);
    console.log('改造响应', JSON.parse(JSON.stringify(json)));

    const accessStore = useAccessStore();

    if (json.code !== 0) {
      if ([401].includes(json.code)) {
        message.error('用户身份过期，请重新登录');

        const authStore = useAuthStore();
        accessStore.setAccessToken(null);
        await authStore.logout();
        // const userStore = useUserStore();
        // userStore.resetStore();
      } else {
        message.error(json.msg || '服务器开小差，请稍后再试');
      }
      // 抛出错误或返回reject状态的Promise实例时，此请求将抛出错误
      throw new Error((json && json.msg) || '出错了');
    }

    // 解析的响应数据将传给method实例的transformData钩子函数，这些函数将在后续讲解
    return json.data;
  }),
});

// 请求配置处理中间件
function requestConfigMiddleware(method: string, url: string) {}

class Http {
  delete(url: string, data?: QueryOptions) {
    return this.request('delete', url, data);
  }

  get(url: string, data?: QueryOptions) {
    return this.request('get', url, data);
  }

  patch(url: string, data?: BodyOptions) {
    return this.request('patch', url, data);
  }

  post(url: string, data?: BodyOptions) {
    return this.request('post', url, data);
  }

  put(url: string, data?: BodyOptions) {
    return this.request('put', url, data);
  }

  private appendParamsToUrl(url: string, params: any): string {
    let queryString = '';
    for (const key in params) {
      if (Object.prototype.hasOwnProperty.call(params, key)) {
        queryString += `${queryString ? '&' : '?'}${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`;
      }
    }
    return url + queryString;
  }

  /**
   * 全局默认配置
   * @param customConfig
   * @returns
   */
  private getConfig(customConfig?: any): any {
    // 递归属性拷贝
    return merge(
      {},
      {
        meta: {
          showLoading: false,
          showError: false,
        },
      },
      customConfig,
    );
  }

  private isBodyOptions(
    options: BodyOptions | QueryOptions,
  ): options is BodyOptions {
    return (options as BodyOptions).data !== undefined;
  }

  /**
   * 适配swagger路径参数，针对于pathParams
   * 输入参数 "/api/v1/user/{id}",{ pathParams:{ id :1 },params:{ id:2 } }
   * 输出请求 /api/v1/user/1?id=2
   */
  private replacePathParams(url: string, pathParams?: any): string {
    if (!pathParams) return url;
    return url.replaceAll(
      /\{(\w+)\}/g,
      (_, key) => pathParams[key] || `{${key}}`,
    );
  }

  private request(
    method: string,
    url: string,
    data?: BodyOptions | QueryOptions,
  ): Promise<any> {
    let finalUrl = this.replacePathParams(url, data?.pathParams);
    const config = this.getConfig(data?.config);

    // 当组件使用allowClear属性时，会将数据置为null，导致数据查询失败
    if (data && data.params) {
      Object.keys(data.params).forEach((key) => {
        if (data.params[key] === null || data.params[key] === undefined) {
          delete data.params[key];
        }
      });
    }
    if (data && this.isBodyOptions(data)) {
      Object.keys(data.data).forEach((key) => {
        if (data.data[key] === null || data.data[key] === undefined) {
          delete data.data[key];
        }
      });
    }

    let alovaMethod: 'Delete' | 'Get' | 'Post' | 'Put' = 'Get';

    if (method === 'get' || method === 'delete') {
      if (method === 'get') {
        alovaMethod = 'Get';
      }
      if (method === 'delete') {
        alovaMethod = 'Delete';
      }
      return alovaInstance[alovaMethod](finalUrl, {
        ...config,
        params: data?.params,
      });
    } else {
      // 处理 params 到 url 的逻辑
      if (data?.params) {
        finalUrl = this.appendParamsToUrl(finalUrl, data.params);
      }
      if (method === 'post') {
        alovaMethod = 'Post';
      }
      if (method === 'put') {
        alovaMethod = 'Put';
      }

      return alovaInstance[alovaMethod](finalUrl, data?.data, { ...config });
    }
  }
}

export const http = new Http();
